import axios from 'axios'
import store from '@/store'
import router from '@/router'
import { Message } from 'element-ui';
import { getToken, setToken, removeToken } from '@/utils/auth'

// create an axios instance
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
  // withCredentials: true, // send cookies when cross-domain requests
  timeout: 5000 // request timeout
})

// request interceptor
service.interceptors.request.use(
  config => {
    if(getToken()){
      config.headers['Authorization'] = `Bearer ${getToken()}`
    }
    return config
  },
  error => {
    console.log(error) // for debug
    return Promise.reject(error)
  }
)

// response interceptor
service.interceptors.response.use(
// 因为后台成功/失败都是200状态码,如何区分成功和失败呢? 用success字段
// request参数, axios响应对象(里面有axios包装的外壳,config/header/data/status……字段)
// data字段里对应的才是后台返回的全部的数据(也是一个对象)
// 第一个data是axios自带的外壳
// 第二个data是后台返回数据对象的
  response => {
    if(response.data.success){
      return response.data
    }else{
      // 逻辑失败(这里通过success字段做判断逻辑,把后台返回message提示文字返回到逻辑页面)
      // 返回Promise的reject拒绝状态(await无法接收失败的promise状态,如果有try catch 进catch里面)
      // 如果这里不返回失败的状态,调用方的catch永远进不去,因为后台返回的状态码是200,所以要在这里进行逻辑判断
      return Promise.reject(response.data.message)
    }
  },
  error => {
    console.dir(error)
    // 4xx/5xx的响应码状态,如果后台返回了失败响应数据,我们就使用,否则就使用error本身的message值
    // 防止null.data报错
    Message.error((error.response && error.response.data && error.response.data.message) || error.message)
    /*
      可以通过http状态码来判断 error.response.status === 401
      或者还可以用code逻辑码来判断(10002 和后台商定的值,代表token过期)
      知识点: ?. (可选链操作符) 新版的语法,需要babel支持才能使用
      左侧有值才会继续往下去点属性(防止空值去.任意的属性报错)
    */
    if(error?.response?.status == 401){
      /*
        token过期需要干的事情
        1 清除 token (vuex和本地的都要删除)
        2 清除用户信息vuex里存储的
        3 返回login页面
      */
      store.dispatch('user/logoutActions') // 清除过期的token + vuex内的state数据
      // 返回login页面(被动退出时,所在页面的路由地址字符串传递给登录页面)
      router.replace(`/login?redirect=${router.currentRoute.fullPath}`) // 退出,可以写在vuex里面但是觉得还是层次分明比较好
    }
    return Promise.reject(error)
  }
)

export default service
